from fastapi import APIRouter, HTTPException, Query, Request, Depends, Path as FastAPIPath, Form
from fastapi.responses import JSONResponse, RedirectResponse
from pathlib import Path
from typing import List, Optional, Any
import logging
import traceback
import uuid
from datetime import datetime

# 从main.py导入templates对象
from app.template_config import templates

# 导入Pydantic模型
from pydantic import BaseModel, Field, field_validator, ValidationError



# 导入服务层
try:
    from app.service.course_service import course_service
    from app.model.course_model import Course
    
except ImportError as e:
    print(f"导入错误: {e}")
    # 确保即使导入失败也不会导致模块无法加载
    course_service = None
    Course = None

# 配置日志 - 更高级的配置
logger = logging.getLogger(__name__)

# 如果logger没有处理器，则添加一个
if not logger.handlers:
    # 创建控制台处理器
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)
    
    # 创建格式化器 - 包含更多上下文信息
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - '  
        'RequestID: %(request_id)s - %(message)s',
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    console_handler.setFormatter(formatter)
    
    # 添加处理器到logger
    logger.addHandler(console_handler)
    logger.setLevel(logging.INFO)


# 创建APIRouter实例
api_router = APIRouter(
    prefix="/api/courses",
    tags=["courses"],
    responses={404: {"description": "Not found"}},
)

# 创建HTML路由实例
router = APIRouter()

# 依赖项：生成请求ID
def get_request_id(request: Request) -> str:
    """生成或获取请求ID"""
    request_id = request.headers.get("X-Request-ID")
    if not request_id:
        request_id = str(uuid.uuid4())
    return request_id


# 自定义日志记录装饰器
def log_operation(operation_name: str):
    """用于记录操作的装饰器"""
    def decorator(func):
        def wrapper(*args, **kwargs):
            # 获取请求和请求ID（从kwargs中）
            request = kwargs.get('request', None)
            request_id = kwargs.get('request_id', 'unknown')
            
            # 添加请求ID到日志记录的extra中
            extra = {'request_id': request_id}
            
            # 记录操作开始
            logger.info(f"开始 {operation_name} 操作", extra=extra)
            
            start_time = datetime.now()
            try:
                # 执行原始函数
                result = func(*args, **kwargs)
                
                # 计算执行时间
                execution_time = (datetime.now() - start_time).total_seconds()
                logger.info(
                    f"{operation_name} 操作成功完成，耗时: {execution_time:.3f}s",
                    extra=extra
                )
                return result
            except Exception as e:
                # 记录操作失败
                execution_time = (datetime.now() - start_time).total_seconds()
                logger.error(
                    f"{operation_name} 操作失败，耗时: {execution_time:.3f}s, 错误: {str(e)}",
                    extra=extra
                )
                raise
        return wrapper
    return decorator


# 自定义错误响应模型
class ErrorResponse(BaseModel):
    error_code: int
    message: str
    detail: Optional[str] = None


# 检查服务是否可用的依赖项
def check_service_availability():
    """检查course_service是否可用"""
    if course_service is None:
        raise HTTPException(
            status_code=503,
            detail="服务暂时不可用，请稍后再试"
        )
    return course_service


# 全局异常处理器
# 注意：异常处理器应该添加到FastAPI主应用实例中，而不是APIRouter
# 此处移除了@router.exception_handler装饰器相关的代码
# 这些异常处理器应该在主应用中实现


# 请求模型 - 创建课程
class CourseCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100, description="课程名称")
    credit: float = Field(..., ge=0.5, le=10.0, description="学分")
    
    @field_validator('credit')
    def validate_credit(cls, v):
        if v <= 0:
            raise ValueError('学分必须大于0')
        return v


# 请求模型 - 更新课程
class CourseUpdate(BaseModel):
    name: Optional[str] = Field(None, min_length=1, max_length=100, description="课程名称")
    credit: Optional[float] = Field(None, ge=0.5, le=10.0, description="学分")
    
    @field_validator('credit')
    def validate_credit(cls, v):
        if v is not None and v <= 0:
            raise ValueError('学分必须大于0')
        return v


# 响应模型 - 课程信息
class CourseResponse(BaseModel):
    id: int
    name: str
    credit: float
    
    class Config:
        from_attributes = True
        
    @classmethod
    def from_course(cls, course: Course) -> 'CourseResponse':
        """从Course模型转换为响应模型"""
        return cls(
            id=course.id,
            name=course.name,
            credit=course.credit
        )


# 创建课程
@api_router.post("/", response_model=CourseResponse, status_code=201)
def create_course_api(
    request: Request,
    course_data: CourseCreate,
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """创建新课程"""
    extra = {'request_id': request_id}
    logger.info(f"收到创建课程请求: 课程名={course_data.name}", extra=extra)
    
    try:
        # 额外的业务逻辑验证
        if len(course_data.name.strip()) == 0:
            raise HTTPException(status_code=400, detail="课程名称不能为空字符串")
            
        # 调用服务层创建课程
        new_course = service.create_course(
            name=course_data.name,
            credit=course_data.credit
        )
        logger.info(f"成功创建课程: ID={new_course.id}, 名称={new_course.name}", extra=extra)
        return CourseResponse.from_course(new_course)
    except HTTPException:
        raise
    except ValueError as e:
        logger.warning(f"创建课程失败: {str(e)}", extra=extra)
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"创建课程时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="创建课程时发生内部错误")


# 获取所有课程
@api_router.get("/", response_model=List[CourseResponse])
def get_all_courses_api(
    request: Request,
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """获取所有课程列表"""
    extra = {'request_id': request_id}
    logger.info("收到获取所有课程请求", extra=extra)
    
    try:
        courses = service.get_all_courses()
        logger.info(f"获取课程列表成功，共 {len(courses)} 个课程", extra=extra)
        return [CourseResponse.from_course(course) for course in courses]
    except Exception as e:
        logger.error(f"获取课程列表时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="获取课程列表时发生内部错误")


# 根据ID获取课程
@api_router.get("/{course_id}", response_model=CourseResponse)
def get_course_by_id_api(
    request: Request,
    course_id: int = FastAPIPath(..., ge=1, description="课程ID"),
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """根据ID获取课程详情"""
    extra = {'request_id': request_id}
    logger.info(f"收到获取课程详情请求: 课程ID={course_id}", extra=extra)
    
    try:
        # 验证course_id参数
        if course_id <= 0:
            raise HTTPException(status_code=400, detail="课程ID必须为正整数")
            
        course = service.get_course_by_id(course_id)
        logger.info(f"获取课程ID {course_id} 成功: 名称={course.name}", extra=extra)
        return CourseResponse.from_course(course)
    except HTTPException:
        raise
    except ValueError as e:
        logger.warning(f"课程ID {course_id} 不存在: {str(e)}", extra=extra)
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f"获取课程ID {course_id} 时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="获取课程详情时发生内部错误")


# 更新课程
@api_router.put("/{course_id}", response_model=CourseResponse)
def update_course_api(
    request: Request,
    course_id: int = FastAPIPath(..., ge=1, description="课程ID"),
    course_data: CourseUpdate = ...,
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """更新课程信息"""
    extra = {'request_id': request_id}
    logger.info(f"收到更新课程请求: 课程ID={course_id}, 更新数据={course_data.model_dump(exclude_unset=True)}", extra=extra)
    
    try:
        # 验证course_id参数
        if course_id <= 0:
            raise HTTPException(status_code=400, detail="课程ID必须为正整数")
            
        # 将Pydantic模型转换为字典并过滤掉None值
        update_data = course_data.model_dump(exclude_unset=True)
        
        # 如果没有提供更新数据
        if not update_data:
            raise HTTPException(status_code=400, detail="至少需要提供一个更新字段")
        
        # 额外的业务逻辑验证
        if 'name' in update_data and len(update_data['name'].strip()) == 0:
            raise HTTPException(status_code=400, detail="课程名称不能为空字符串")
        
        updated_course = service.update_course(
            course_id,
            **update_data
        )
        logger.info(f"更新课程ID {course_id} 成功: 新名称={updated_course.name}", extra=extra)
        return CourseResponse.from_course(updated_course)
    except HTTPException:
        raise
    except ValueError as e:
        logger.warning(f"更新课程ID {course_id} 失败: {str(e)}", extra=extra)
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"更新课程ID {course_id} 时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="更新课程时发生内部错误")


# 删除课程
@api_router.delete("/{course_id}", status_code=204)
def delete_course_api(
    request: Request,
    course_id: int = FastAPIPath(..., ge=1, description="课程ID"),
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """删除课程"""
    extra = {'request_id': request_id}
    logger.info(f"收到删除课程请求: 课程ID={course_id}", extra=extra)
    
    try:
        # 验证course_id参数
        if course_id <= 0:
            raise HTTPException(status_code=400, detail="课程ID必须为正整数")
            
        service.delete_course(course_id)
        logger.info(f"删除课程ID {course_id} 成功", extra=extra)
        return None
    except HTTPException:
        raise
    except ValueError as e:
        logger.warning(f"删除课程ID {course_id} 失败: {str(e)}", extra=extra)
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f"删除课程ID {course_id} 时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="删除课程时发生内部错误")


# 根据名称搜索课程
@api_router.get("/search/name", response_model=List[CourseResponse])
def search_courses_by_name_api(
    request: Request,
    keyword: str = Query(..., min_length=1, max_length=100, description="搜索关键字"),
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """根据课程名称搜索课程"""
    extra = {'request_id': request_id}
    logger.info(f"收到搜索课程请求: 关键字='{keyword}'", extra=extra)
    
    try:
        # 额外的参数验证
        if not keyword or keyword.isspace():
            raise HTTPException(status_code=400, detail="搜索关键字不能为空或只包含空格")
            
        courses = service.search_courses_by_name(keyword)
        logger.info(f"搜索课程关键字 '{keyword}' 成功，共找到 {len(courses)} 个课程", extra=extra)
        return [CourseResponse.from_course(course) for course in courses]
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"搜索课程时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="搜索课程时发生内部错误")


# 根据学分范围查询课程
@api_router.get("/search/credit", response_model=List[CourseResponse])
def get_courses_by_credit_range_api(
    request: Request,
    min_credit: float = Query(..., ge=0.5, le=10.0, description="最小学分"),
    max_credit: float = Query(..., ge=0.5, le=10.0, description="最大学分"),
    request_id: str = Depends(get_request_id),
    service: Any = Depends(check_service_availability)
):
    """根据学分范围查询课程"""
    extra = {'request_id': request_id}
    logger.info(f"收到按学分范围查询课程请求: 范围={min_credit}-{max_credit}", extra=extra)
    
    try:
        # 验证学分范围
        if min_credit > max_credit:
            raise HTTPException(status_code=400, detail="最小学分不能大于最大学分")
            
        if min_credit < 0 or max_credit < 0:
            raise HTTPException(status_code=400, detail="学分必须为正数")
        
        courses = service.get_courses_by_credit_range(min_credit, max_credit)
        logger.info(f"查询学分范围 {min_credit}-{max_credit} 的课程成功，共找到 {len(courses)} 个课程", extra=extra)
        return [CourseResponse.from_course(course) for course in courses]
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"按学分范围查询课程时发生错误: {str(e)}", extra=extra)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail="按学分范围查询课程时发生内部错误")


# HTML路由函数
@router.get("/courses")
def get_courses_html(request: Request):
    """显示所有课程的HTML页面"""
    try:
        courses = course_service.get_all_courses()
        return templates.TemplateResponse("courses.html", {"request": request, "courses": courses, "messages": []})
    except Exception as e:
        return templates.TemplateResponse("courses.html", {"request": request, "courses": [], "error": str(e), "messages": []})


@router.get("/courses/create")
def create_course_html(request: Request):
    """显示创建课程的表单页面"""
    return templates.TemplateResponse("create_course.html", {"request": request, "messages": []})


@router.get("/courses/{course_id}")
def get_course_html(request: Request, course_id: int = FastAPIPath(..., ge=1)):
    """显示单个课程详情的HTML页面"""
    try:
        course = course_service.get_course_by_id(course_id)
        return templates.TemplateResponse("course_detail.html", {"request": request, "course": course, "messages": []})
    except ValueError as e:
        return templates.TemplateResponse("course_detail.html", {"request": request, "course": None, "error": str(e), "messages": []})
    except Exception as e:
        return templates.TemplateResponse("course_detail.html", {"request": request, "course": None, "error": "获取课程详情失败", "messages": []})


@router.post("/courses/create")
def create_course_html(request: Request, name: str = Form(...), credit: float = Form(...)):
    """处理创建课程的表单提交"""
    try:
        # 直接传递参数给service层
        course_service.create_course(name=name, credit=credit)
        return RedirectResponse(url="/courses", status_code=302)
    except ValueError as e:
        return templates.TemplateResponse("create_course.html", {"request": request, "error": str(e), "name": name, "credit": credit, "messages": []})
    except Exception as e:
          return templates.TemplateResponse("create_course.html", {"request": request, "error": "创建课程失败", "name": name, "credit": credit, "messages": []})


@router.get("/courses/{course_id}/edit")
def edit_course_html(request: Request, course_id: int = FastAPIPath(..., ge=1)):
    """显示编辑课程的表单页面"""
    try:
        course = course_service.get_course_by_id(course_id)
        return templates.TemplateResponse("edit_course.html", {"request": request, "course": course, "messages": []})
    except ValueError as e:
        return templates.TemplateResponse("edit_course.html", {"request": request, "course": None, "error": str(e), "messages": []})
    except Exception as e:
        return templates.TemplateResponse("edit_course.html", {"request": request, "course": None, "error": "获取课程信息失败", "messages": []})


@router.post("/courses/{course_id}/edit")
def edit_course_html(request: Request, course_id: int = FastAPIPath(..., ge=1), name: str = Form(...), credit: float = Form(...)):
    """处理编辑课程的表单提交"""
    try:
        # 直接传递参数给service层
        course_service.update_course(course_id, name=name, credit=credit)
        return RedirectResponse(url=f"/courses/{course_id}", status_code=302)
    except ValueError as e:
        # 获取当前课程信息以显示在表单中
        try:
            current_course = course_service.get_course_by_id(course_id)
        except:
            current_course = None
        return templates.TemplateResponse("edit_course.html", {"request": request, "course": current_course, "error": str(e), "messages": []})
    except Exception as e:
        try:
            current_course = course_service.get_course_by_id(course_id)
        except:
            current_course = None
        return templates.TemplateResponse("edit_course.html", {"request": request, "course": current_course, "error": "更新课程失败", "messages": []})


@router.post("/courses/{course_id}/delete")
def delete_course_html(request: Request, course_id: int = FastAPIPath(..., ge=1)):
    """处理删除课程的请求"""
    try:
        course_service.delete_course(course_id)
        return RedirectResponse(url="/courses", status_code=303)
    except ValueError as e:
        # 删除失败后重定向回课程列表
        courses = course_service.get_all_courses() if course_service else []
        return templates.TemplateResponse("courses.html", {"request": request, "courses": courses, "error": str(e), "messages": []})
    except Exception as e:
        # 记录错误但仍重定向回课程列表
        courses = course_service.get_all_courses() if course_service else []
        return templates.TemplateResponse("courses.html", {"request": request, "courses": courses, "error": "删除课程失败", "messages": []})


# 将API路由添加到主路由
router.include_router(api_router)